https://www.donneesquebec.ca/recherche/dataset/vmtl-actes-criminels, Liste des actes criminels enregistrés par le Service de police de la Ville de Montréal (SPVM).
Liste des actes criminels enregistrés par le Service de police de la Ville de Montréal (SPVM). Criminalité - 2015 à aujourd’hui ## Importer données à partir du WEB
Il faut d’abord importer les données et s’assurer du format de celle-ci. Un simple head() est suffisant pour nos besoins.
data_URL <- "https://data.montreal.ca/dataset/5829b5b0-ea6f-476f-be94-bc2b8797769a/resource/c6f482bf-bf0f-4960-8b2f-9982c211addd/download/interventionscitoyendo.csv"
dat <- read.csv(file = data_URL)
head(dat)
## CATEGORIE DATE QUART PDQ X Y
## 1 Vol de v\xe9hicule \xe0 moteur 2018-09-13 jour 30 294904.2 5047549
## 2 Vol de v\xe9hicule \xe0 moteur 2018-04-30 jour 30 294904.2 5047549
## 3 Vol de v\xe9hicule \xe0 moteur 2018-09-01 nuit 7 290274.6 5042150
## 4 M\xe9fait 2017-07-21 jour 21 0.0 0
## 5 M\xe9fait 2017-07-29 jour 12 0.0 0
## 6 Vol de v\xe9hicule \xe0 moteur 2017-07-30 nuit 21 0.0 0
## LONGITUDE LATITUDE
## 1 -73.62678 45.56778
## 2 -73.62678 45.56778
## 3 -73.68593 45.51912
## 4 -76.23729 0.00000
## 5 -76.23729 0.00000
## 6 -76.23729 0.00000
premier problème, les accents sont bizarres… que faire? Dans les informations complémentaires sur la page de téléchargement des données, il est inscrit: > Encodage de caractères > Le fichier CSV utilise l’encodage de caractère ISO-8859-1 (latin1)
Il doit bien y avoir une façon de lire le fichier en spécifiant un encodage particulier.
?read.csv
Dans l’aide, on y retrouve un argument ou deux arguments qui nous mèneront peut-être au résultat espérer, soit fileEncoding = "" et encoding = "unknown",
read.table(file, header = FALSE, sep = "", quote = "\"'",
dec = ".", numerals = c("allow.loss", "warn.loss", "no.loss"),
row.names, col.names, as.is = !stringsAsFactors,
na.strings = "NA", colClasses = NA, nrows = -1,
skip = 0, check.names = TRUE, fill = !blank.lines.skip,
strip.white = FALSE, blank.lines.skip = TRUE,
comment.char = "#",
allowEscapes = FALSE, flush = FALSE,
stringsAsFactors = default.stringsAsFactors(),
fileEncoding = "", encoding = "unknown", text, skipNul = FALSE)
fileEncoding: character string: if non-empty declares the encoding used on a file (not a connection) so the character data can be re-encoded. See the ‘Encoding’ section of the help for file, the ‘R Data Import/Export Manual’ and ‘Note’.
encoding: encoding to be assumed for input strings. It is used to mark character strings as known to be in Latin-1 or UTF-8 (see Encoding): it is not used to re-encode the input, but allows R to handle encoded strings in their native encoding (if one of those two). See ‘Value’ and ‘Note’.
En lisant les deux options, il est difficile de savoir quel argument nous devons choisir. Heureusement, la section Note précise que les deux peuvent être utilisé selon le format d’encodage de l’input: > Note > There are two approaches for reading input that is not in the local encoding. If the input is known to be UTF-8 or Latin1, use the encoding argument to declare that. If the input is in some other encoding, then it may be translated on input. The fileEncoding argument achieves this by setting up a connection to do the re-encoding into the current locale. Note that on Windows or other systems not running in a UTF-8 locale, this may not be possible.
À ce stade de confusion, nous pouvons essayer les deux options et observer les différences..
head(read.csv(file = data_URL, encoding = "Latin1"))
## CATEGORIE DATE QUART PDQ X Y
## 1 Vol de v\xe9hicule \xe0 moteur 2018-09-13 jour 30 294904.2 5047549
## 2 Vol de v\xe9hicule \xe0 moteur 2018-04-30 jour 30 294904.2 5047549
## 3 Vol de v\xe9hicule \xe0 moteur 2018-09-01 nuit 7 290274.6 5042150
## 4 M\xe9fait 2017-07-21 jour 21 0.0 0
## 5 M\xe9fait 2017-07-29 jour 12 0.0 0
## 6 Vol de v\xe9hicule \xe0 moteur 2017-07-30 nuit 21 0.0 0
## LONGITUDE LATITUDE
## 1 -73.62678 45.56778
## 2 -73.62678 45.56778
## 3 -73.68593 45.51912
## 4 -76.23729 0.00000
## 5 -76.23729 0.00000
## 6 -76.23729 0.00000
head(read.csv(file = data_URL, fileEncoding = "Latin1"))
## CATEGORIE DATE QUART PDQ X Y LONGITUDE
## 1 Vol de véhicule à moteur 2018-09-13 jour 30 294904.2 5047549 -73.62678
## 2 Vol de véhicule à moteur 2018-04-30 jour 30 294904.2 5047549 -73.62678
## 3 Vol de véhicule à moteur 2018-09-01 nuit 7 290274.6 5042150 -73.68593
## 4 Méfait 2017-07-21 jour 21 0.0 0 -76.23729
## 5 Méfait 2017-07-29 jour 12 0.0 0 -76.23729
## 6 Vol de véhicule à moteur 2017-07-30 nuit 21 0.0 0 -76.23729
## LATITUDE
## 1 45.56778
## 2 45.56778
## 3 45.51912
## 4 0.00000
## 5 0.00000
## 6 0.00000
Il semble que l’argument fileEncoding remporte! Nous pouvons donc réimporter les données comme il faut. Nous pourrions également downloader les données pour être sûr d’avoir une copie locale, advenant que le site disparait du Web.
dat <- read.csv(file = data_URL, fileEncoding = "Latin1")
# download.file(url = data_URL, destfile = "copie_locale.csv")
Maintenant que le jeu de données est importé, regardons voir si on comprend bien comment il est structuré.
dim(dat)
## [1] 202441 8
summary(dat)
## CATEGORIE DATE QUART PDQ
## Length:202441 Length:202441 Length:202441 Min. : 1.0
## Class :character Class :character Class :character 1st Qu.:15.0
## Mode :character Mode :character Mode :character Median :26.0
## Mean :26.4
## 3rd Qu.:39.0
## Max. :55.0
## NA's :4
## X Y LONGITUDE LATITUDE
## Min. : 0 Min. : 0 Min. :-76.24 Min. : 0.00
## 1st Qu.:288271 1st Qu.:5035102 1st Qu.:-73.71 1st Qu.:45.46
## Median :295887 Median :5041400 Median :-73.61 Median :45.51
## Mean :244829 Mean :4173825 Mean :-74.07 Mean :37.68
## 3rd Qu.:299207 3rd Qu.:5045887 3rd Qu.:-73.57 3rd Qu.:45.55
## Max. :306390 Max. :5062496 Max. :-73.48 Max. :45.70
##
On remarque 202375 observations et 8 variables CATEGORIE, DATE, QUART, PDQ, X, Y, LONGITUDE, LATITUDE. Certaines variables sont plutôt difficile à savoir ce qu’elles représentent, principalement PDF, X et Y et qu’il semble y avoir des 0 et des valeurs manquantes pour d’autres. Heureusement, il y a un Dictionnaire de données dans les informations complémentaires.
Dictionnaire de données
CATEGORIE : Nature de l'événement. Liste de valeur :
Introduction : introduction par effraction dans un établissement public ou une résidence privée, vol d’arme à feu dans une résidence
Vol dans / sur véhicule à moteur : vol du contenu d’un véhicule à moteur (voiture, camion, motocyclette, etc.) ou d’une pièce de véhicule (roue, parechoc, etc.)
Vol de véhicule à moteur : vol de voiture, camion, motocyclette, motoneige tracteur avec ou sans remorque, véhicule de construction ou de ferme, tout-terrain
Méfait : Graffiti et dommage de biens religieux, de véhicule ou dommage général et tous autres types de méfaits
Vol qualifié : Vol accompagné de violence de commerce, institution financière, personne, sac à main, véhicule blindé, véhicule, arme à feu, et tous autres types de vols qualifiés
Infraction entraînant la mort : Meurtre au premier degré, meurtre au deuxième degré, homicide involontaire, infanticide, négligence criminelle, et tous autres types d’infractions entraînant la mort
DATE : Date du signalement de l'événement au SPVM au format AAAA-MM-JJ HH:mm:ss (note: la partie de l'heure n'est pas utilisée)
QUART : Moment de la journée du signalement de l'événement au SPVM. Liste de valeur :
jour : Entre 8h01 et 16h
soir : Entre 16h01 et minuit
nuit : Entre 00h01 et 8h
PDQ : Numéro du poste de quartier couvrant le territoire où s'est passé l'événement. Le territoire couvert par chaque poste est disponible dans l'ensemble de données des limites de PDQ
X et Y : Position géospatiale selon la projection MTM8 (SRID 2950)
La valeur 0 est utilisée lorsqu'aucune position géographique n'a été fournie lors de la saisie de l'information.
LAT et LONG: position géographique de l'événement après obfuscation à une intersection selon le référentiel géodésique WGS84.
La valeur 1 est utilisée lorsqu'aucune position géographique n'a été fournie lors de la saisie de l'information.
À partir de ces infos, il faudrait déjà se questionner à propos de ce que nous ferons des 0 et des 1 pour les données géographiques, car celles-ci causeront problèmes pour la visualisation.
Mais avant, assurons-nous que les valeurs représentent bien le type de données que nous avons. Il y a, entre autres, DATE qui semble n’être que des chaines de caractères et PDQ des nombres entiers alors qu’ils représentent les numéros des postes de quartier.
Au-delà de la chaine de caractères, certaines données sont, en réalité, des facteurs, un type de structure de données dédié pour les données catégo- rielles qui permet d’automatiser plusieurs traitements. Quelles colonnes selon vous représentent des facteurs dans cet ensemble de données?
dat$DATE <- as.Date(dat$DATE)
# 1ère façon de faire "manuelle" pour convertir en facteurs
dat$PDQ <- as.factor(dat$PDQ)
dat$CATEGORIE <- as.factor(dat$CATEGORIE)
dat$QUART <- as.factor(dat$QUART)
# 2e façon de faire
vars <- c("CATEGORIE", "PDQ", "QUART")
dat[vars] <- lapply(dat[vars], as.factor)
summary(dat)
## CATEGORIE DATE QUART
## Infractions entrainant la mort : 177 Min. :2015-01-01 jour:102500
## Introduction :53039 1st Qu.:2016-06-21 nuit: 30853
## Méfait :45952 Median :2017-12-17 soir: 69088
## Vol dans / sur véhicule à moteur:60410 Mean :2018-02-25
## Vol de véhicule à moteur :31151 3rd Qu.:2019-10-18
## Vols qualifiés :11712 Max. :2021-10-08
##
## PDQ X Y LONGITUDE
## 38 : 14293 Min. : 0 Min. : 0 Min. :-76.24
## 21 : 11829 1st Qu.:288271 1st Qu.:5035102 1st Qu.:-73.71
## 20 : 11249 Median :295887 Median :5041400 Median :-73.61
## 48 : 9790 Mean :244829 Mean :4173825 Mean :-74.07
## 39 : 9185 3rd Qu.:299207 3rd Qu.:5045887 3rd Qu.:-73.57
## (Other):146091 Max. :306390 Max. :5062496 Max. :-73.48
## NA's : 4
## LATITUDE
## Min. : 0.00
## 1st Qu.:45.46
## Median :45.51
## Mean :37.68
## 3rd Qu.:45.55
## Max. :45.70
##
Maintenant que nous avons ce qu’il nous faut, il serait intéressant de voir si la criminalité augmente ou diminue entre chaque année.
Est-ce la même tendance pour chaque catégorie de crimes?
# format(dat$DATE, "%Y")
dat$DATE_year <- format(dat$DATE, "%Y")
dat$DATE_month <- format(dat$DATE, "%m")
dat$DATE_month_year <- format(dat$DATE, c("Y%","%m"))
library(ggplot2)
# Make xtables
freq_year <- as.data.frame(table(dat$CATEGORIE, dat$DATE_year, useNA = "ifany"))
colnames(freq_year) <- c("CATEGORIE", "YEAR", "Freq")
freq_month_year <- as.data.frame(table(dat$CATEGORIE, dat$DATE_year, dat$DATE_month, useNA = "ifany"))
colnames(freq_month_year) <- c("CATEGORIE", "YEAR", "MONTH", "Freq")
ggplot(freq_year, aes(x = YEAR, y = Freq, group = CATEGORIE, color = CATEGORIE)) +
geom_line(size = 1.5) +
theme_bw() +
labs(title = "Évolution annuelle de la criminalité rapportée depuis 2015 à Montréal",
x = "Années",
y = "Nombre de crimes") +
theme(text=element_text(size = 16),
axis.text.x = element_text(angle = 45, hjust = 0.5, vjust = 0.5)) + geom_point(size = 3)
ggplot(freq_month_year, aes(x = MONTH, y = Freq, group = CATEGORIE, color = CATEGORIE)) + geom_line(size=1.5) +
facet_wrap(facets = vars(YEAR)) + geom_line(size = 1.5) +
theme_bw() +
labs(title = "Évolution annuelle de la criminalité rapportée depuis 2015 à Montréal",
x = "Années",
y = "Nombre de crimes") +
theme(text=element_text(size = 16),
axis.text.x = element_text(angle = 45, hjust = 0.5, vjust = 0.5)) + geom_point(size = 3)
ggplot(freq_month_year, aes(x = YEAR, y = Freq, group = CATEGORIE, color = CATEGORIE)) + geom_line(size=1.5) +
facet_wrap(facets = vars(MONTH)) + geom_line(size = 1.5) +
theme_bw() +
labs(title = "Évolution annuelle de la criminalité rapportée depuis 2015 à Montréal",
x = "Années",
y = "Nombre de crimes") +
theme(text=element_text(size = 16),
axis.text.x = element_text(angle = 45, hjust = 0.5, vjust = 0.5)) + geom_point(size = 3)
Et une map peut-être?
#install.packages("leaflet")
library(leaflet)
m <- leaflet(options = leafletOptions(minZoom = 10, maxZoom = 18))
m <- addTiles(m)
m <- setView(m, lng = -73.58781, lat = 45.50884, zoom = 11)
m <- addProviderTiles(m, providers$CartoDB.DarkMatter)
dat$COLOR <- sapply(dat$CATEGORIE, function(CATEGORIE) {
if(CATEGORIE == "Infractions entrainant la mort") {
"red"
} else if(CATEGORIE == "Introduction") {
"pink"
} else if(CATEGORIE == "Méfait") {
"orange"
} else if(CATEGORIE == "Vol dans / sur véhicule à moteur") {
"green"
} else if(CATEGORIE == "Vol de véhicule à moteur") {
"blue"
} else {
"black"
} })
icons <- awesomeIcons(
icon = 'ios-close',
iconColor = 'black',
library = 'ion',
markerColor = dat$COLOR
)
m <- addAwesomeMarkers(m, lng = dat$LONGITUDE, lat = dat$LATITUDE, icon = icons, label = paste(dat$QUART, "-", dat$CATEGORIE), clusterOptions = markerClusterOptions())
m